﻿using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Text.Json;

namespace Pay.Core
{
    /// <summary>
    /// EnumConverter
    /// </summary>
    public class EnumConverter<T> : JsonConverter<T> where T : struct, Enum
    {
        /// <summary>
        /// CanConvert
        /// </summary>
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert.IsEnum;
        }

        /// <summary>
        /// Read
        /// </summary>
        public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var tokenType = reader.TokenType;
            var srcValue = string.Empty;
            if (tokenType == JsonTokenType.String)
                srcValue = reader.GetString();
            else if (tokenType == JsonTokenType.Number)
                srcValue = reader.GetInt32().ToString();

            if (!string.IsNullOrWhiteSpace(srcValue) && Enum.TryParse<T>(srcValue, true, out T value))
                return value;
            else
                throw new NotSupportedException("不支持枚举转换");
        }

        /// <summary>
        /// Write
        /// </summary>
        public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
        {
            writer.WriteNumberValue(Unsafe.As<T, int>(ref value));
        }
    }

    /// <summary>
    /// JsonEnumConverter
    /// </summary>
    public class JsonEnumConverter : JsonConverterFactory
    {
        /// <summary>
        /// CanConvert
        /// </summary>
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert.IsEnum;
        }

        /// <summary>
        /// CreateConverter
        /// </summary>
        public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            var convertType = typeof(EnumConverter<>).MakeGenericType(typeToConvert);
            return (JsonConverter)Activator.CreateInstance(convertType);
        }
    }
}
